package com.tbi.graphcolouring.appframe;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import net.miginfocom.swing.MigLayout;

import com.tbi.graphcolouring.AlgorithmSettings;
import com.tbi.graphcolouring.algorithmconfiguration.creator.RandomPopulationCreator;
import com.tbi.graphcolouring.algorithmconfiguration.crosser.MultiPointCrosser;
import com.tbi.graphcolouring.algorithmconfiguration.evaluator.PunishmentEvaluator;
import com.tbi.graphcolouring.algorithmconfiguration.evaluator.RepairEvaluator;
import com.tbi.graphcolouring.algorithmconfiguration.mutator.SinglePointMutator;
import com.tbi.graphcolouring.algorithmconfiguration.selector.ExponentialRankingSelector;
import com.tbi.graphcolouring.algorithmconfiguration.selector.GaussianRankingSelector;
import com.tbi.graphcolouring.algorithmconfiguration.selector.TournamentSelector;
import com.tbi.graphcolouring.algorithmconfiguration.stopper.GenerationStopper;
import com.tbi.graphcolouring.algorithmconfiguration.stopper.NoImprovementStopper;

@SuppressWarnings("serial")
public class ConfigDialog extends JDialog {

	private final JPanel contentPanel = new JPanel();
	private JLabel lblPopulationSize;
	private JSpinner spinner_1;
	private JRadioButton rdbtnNewRadioButton;
	private JRadioButton rdbtnNewRadioButton_1;
	private JSpinner spinner_2;
	private JRadioButton rdbtnNewRadioButton_2;
	private JRadioButton rdbtnNewRadioButton_3;
	private JSpinner spinner_3;
	private JSpinner spinner_4;
	private JRadioButton rdbtnSelectUsingGaussian;
	private JRadioButton rdbtnSelectUsingExponential;
	private JSpinner spinner_5;
	private JSpinner spinner_6;
	private JCheckBox chckbxRandomizeNumberOf;
	private JSpinner spinner;
	private JCheckBox chckbxEnableEntityNormalization;
	private JSpinner spinner_7;
	private JRadioButton rdbtnNewRadioButton_4;
	private JLabel lblTournamentGroupSize;
	private JSpinner spinner_8;

	public static void open(JFrame owner) {
		try {
			ConfigDialog dialog = new ConfigDialog(owner);
			dialog.loadCurrentSettings();
			dialog.setOKEvent();
			dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			dialog.setVisible(true);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void setOKEvent() {
		Object selectionFactorSpinnerValue = getSelectionFactorSpinner().getValue();
		Object crossoverProbabilitySpinnerValue = getCrossoverProbabilitySpinner().getValue();
		Object mutationProbabilitySpinnerValue = getMutationProbabilitySpinner().getValue();
		
		AlgorithmSettings.POPULATION_SIZE = (int) getPopulationSizeSpinner().getValue();
		AlgorithmSettings.EVALUATION_PUNISHMENT = (int) getEvaluatorPunishmentSpinner().getValue();
		AlgorithmSettings.GENERATIONS_LIMIT = (int) getGenerationsLimitSpinner().getValue();
		AlgorithmSettings.GENERATIONS_WITHOUT_IMPROVEMENT_LIMIT = (int) getGenerationsWithoutImprovementLimitSpinner().getValue();
		AlgorithmSettings.RANDOMIZE_NUMBER_OF_CROSS_POINTS = getRandomizeNumberOfCrossPointsCheckBox().isSelected();
		AlgorithmSettings.NUMBER_OF_CROSS_POINTS = (int) getNumberOfCrossPointsSpinner().getValue();
		AlgorithmSettings.ENABLE_ENTITY_NORMALIZATION = getEnableEntityNormalizationCheckBox().isSelected();
		System.out.println(getMutationProbabilitySpinner().getValue().getClass());
		
		AlgorithmSettings.MUTATION_PROBABILITY = mutationProbabilitySpinnerValue instanceof Float ?
				(float)mutationProbabilitySpinnerValue / 100f : ((Integer)mutationProbabilitySpinnerValue).floatValue() / 100f;
		AlgorithmSettings.CROSSOVER_PROBABILITY = crossoverProbabilitySpinnerValue instanceof Float ?
				(float)crossoverProbabilitySpinnerValue / 100f : ((Integer)crossoverProbabilitySpinnerValue).floatValue() / 100f;
		AlgorithmSettings.SELECTION_FACTOR = selectionFactorSpinnerValue instanceof Float ?
				(float)selectionFactorSpinnerValue / 100f : ((Integer)selectionFactorSpinnerValue).floatValue() / 100f;
		
		AlgorithmSettings.populationCreator = new RandomPopulationCreator(AlgorithmSettings.POPULATION_SIZE);
		if(getEvaluationWithPunishmentRadioButton().isSelected()){
			AlgorithmSettings.evaluator = new PunishmentEvaluator(AlgorithmSettings.graph);
		} else {
			AlgorithmSettings.evaluator = new RepairEvaluator(AlgorithmSettings.graph);
		}
		if(getGenerationLimitRadioButton().isSelected()){
			AlgorithmSettings.algorithmStopper = new GenerationStopper(AlgorithmSettings.GENERATIONS_LIMIT);
		} else {
			AlgorithmSettings.algorithmStopper = new NoImprovementStopper(AlgorithmSettings.GENERATIONS_WITHOUT_IMPROVEMENT_LIMIT);
		}
		if(getSelectUsingGaussianRadioButton().isSelected()){
			AlgorithmSettings.selector = new GaussianRankingSelector();
		} else if(getSelectUsingExponentialRadioButton().isSelected()){
			AlgorithmSettings.selector = new ExponentialRankingSelector();
		} else if(getTournamentSelectionRadioButton().isSelected()){
			AlgorithmSettings.selector = new TournamentSelector();
		}
		AlgorithmSettings.crosser = new MultiPointCrosser();
		AlgorithmSettings.mutator = new SinglePointMutator();
		
		this.dispose();
	}
	
	private void loadCurrentSettings() {
		getPopulationSizeSpinner().setValue(AlgorithmSettings.POPULATION_SIZE);
		getEvaluatorPunishmentSpinner().setValue(AlgorithmSettings.EVALUATION_PUNISHMENT);
		getGenerationsWithoutImprovementRadioButton().doClick();
		getGenerationsLimitSpinner().setValue(AlgorithmSettings.GENERATIONS_LIMIT);
		getGenerationsWithoutImprovementLimitSpinner().setValue(AlgorithmSettings.GENERATIONS_WITHOUT_IMPROVEMENT_LIMIT);
		getSelectionFactorSpinner().setValue(AlgorithmSettings.SELECTION_FACTOR*100);
		getSelectUsingGaussianRadioButton().doClick();
		getCrossoverProbabilitySpinner().setValue(AlgorithmSettings.CROSSOVER_PROBABILITY*100);
		if(AlgorithmSettings.RANDOMIZE_NUMBER_OF_CROSS_POINTS){
			getRandomizeNumberOfCrossPointsCheckBox().doClick();
		}
		getNumberOfCrossPointsSpinner().setValue(AlgorithmSettings.NUMBER_OF_CROSS_POINTS);
		if(AlgorithmSettings.ENABLE_ENTITY_NORMALIZATION){
			getEnableEntityNormalizationCheckBox().doClick();
		}
		getMutationProbabilitySpinner().setValue(AlgorithmSettings.MUTATION_PROBABILITY * 100);
		getTournamentGroupSizeSpinner().setValue(AlgorithmSettings.TOURNAMENT_GROUP_SIZE);
		
		if(AlgorithmSettings.evaluator instanceof PunishmentEvaluator){
			getEvaluationWithPunishmentRadioButton().doClick();
		} else if(AlgorithmSettings.evaluator instanceof RepairEvaluator){
			getEvaluationWithRepairRadioButton().doClick();
		}
		
		if(AlgorithmSettings.selector instanceof ExponentialRankingSelector){
			getSelectUsingExponentialRadioButton().doClick();
		} else if(AlgorithmSettings.selector instanceof GaussianRankingSelector){
			getSelectUsingGaussianRadioButton().doClick();
		} else if(AlgorithmSettings.selector instanceof TournamentSelector){
			getTournamentSelectionRadioButton().doClick();
		}
		
		if(AlgorithmSettings.algorithmStopper instanceof GenerationStopper){
			getGenerationLimitRadioButton().doClick();
		} else if(AlgorithmSettings.algorithmStopper instanceof NoImprovementStopper){
			getGenerationsWithoutImprovementRadioButton().doClick();
		}
	}

	/**
	 * Create the dialog.
	 */
	private ConfigDialog(JFrame owner) {
		super(owner, true);
		setSize(343, 277);
		setLocationRelativeTo(owner);
		getContentPane().setLayout(new BorderLayout());
		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
		getContentPane().add(contentPanel, BorderLayout.CENTER);
		contentPanel.setLayout(new BorderLayout(0, 0));
		
		JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		contentPanel.add(tabbedPane);
		{
			JPanel panel = new JPanel();
			tabbedPane.addTab("Creator", null, panel, null);
			panel.setLayout(new MigLayout("", "[10px:n][][60px:n]", "[]"));
			{
				lblPopulationSize = new JLabel("Population size:");
				panel.add(lblPopulationSize, "cell 1 0");
			}
			{
				spinner_1 = new JSpinner();
				lblPopulationSize.setLabelFor(spinner_1);
				spinner_1.setEnabled(true);
				panel.add(spinner_1, "cell 2 0,grow");
			}
		}
		{
			JPanel panel = new JPanel();
			tabbedPane.addTab("Evaluator", null, panel, null);
			panel.setLayout(new MigLayout("", "[][][][50px:n:50px]", "[][][][]"));
			{
				ButtonGroup evaluationRadioButtons = new ButtonGroup();
				
				rdbtnNewRadioButton = new JRadioButton("Evaluation with repair");
				evaluationRadioButtons.add(rdbtnNewRadioButton);
				panel.add(rdbtnNewRadioButton, "cell 0 0");

				rdbtnNewRadioButton_1 = new JRadioButton("Evaluation with punishment");
				evaluationRadioButtons.add(rdbtnNewRadioButton_1);
				panel.add(rdbtnNewRadioButton_1, "cell 0 1");

				JLabel lblNewLabel = new JLabel("       Punishment");
				panel.add(lblNewLabel, "cell 2 1");
				
				spinner_2 = new JSpinner();
				panel.add(spinner_2, "cell 3 1,growx");
				
				ActionListener cl = new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						if(e.getSource() == rdbtnNewRadioButton_1){
							spinner_2.setEnabled(true);
						}else{
							spinner_2.setEnabled(false);
						}
					}
				};
				
				rdbtnNewRadioButton.addActionListener(cl);
				rdbtnNewRadioButton_1.addActionListener(cl);
			}
		}
		{
			JPanel panel = new JPanel();
			tabbedPane.addTab("Stopper", null, panel, null);
			panel.setLayout(new MigLayout("", "[][][][50px:n:50px]", "[][]"));
			
			ButtonGroup stopperRadioButtons = new ButtonGroup();
			{
				rdbtnNewRadioButton_2 = new JRadioButton("Generations limit");
				stopperRadioButtons.add(rdbtnNewRadioButton_2);
				panel.add(rdbtnNewRadioButton_2, "cell 0 0");

				JLabel lblLimit = new JLabel("Limit:");
				panel.add(lblLimit, "cell 2 0");

				spinner_3 = new JSpinner();
				panel.add(spinner_3, "cell 3 0,growx");

				rdbtnNewRadioButton_3 = new JRadioButton("Generation without improvement limit");
				stopperRadioButtons.add(rdbtnNewRadioButton_3);
				panel.add(rdbtnNewRadioButton_3, "cell 0 1");

				JLabel lblLimit_1 = new JLabel("Limit:");
				panel.add(lblLimit_1, "cell 2 1");

				spinner_4 = new JSpinner();
				panel.add(spinner_4, "cell 3 1,growx");
				
				ActionListener al = new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						if(e.getSource() == rdbtnNewRadioButton_2){
							spinner_3.setEnabled(true);
							spinner_4.setEnabled(false);
						}else{
							spinner_4.setEnabled(true);
							spinner_3.setEnabled(false);
						}
					}
				};
				
				getGenerationLimitRadioButton().addActionListener(al);
				getGenerationsWithoutImprovementRadioButton().addActionListener(al);
			}
		}
		{
			JPanel panel = new JPanel();
			tabbedPane.addTab("Selector", null, panel, null);
			panel.setLayout(new MigLayout("", "[][]", "[][][][][]"));

			ButtonGroup selectorRadioButtons = new ButtonGroup();
			{
				rdbtnSelectUsingGaussian = new JRadioButton("Select using gaussian distribution");
				selectorRadioButtons.add(rdbtnSelectUsingGaussian);
				panel.add(rdbtnSelectUsingGaussian, "cell 0 0 2 1");

				rdbtnSelectUsingExponential = new JRadioButton("Select using exponential distribution");
				selectorRadioButtons.add(rdbtnSelectUsingExponential);
				panel.add(rdbtnSelectUsingExponential, "cell 0 1 2 1");

				JLabel lblSelectionFactor = new JLabel("       Selection factor (%)");
				panel.add(lblSelectionFactor, "cell 0 2");

				spinner_5 = new JSpinner();
				panel.add(spinner_5, "cell 1 2,growx");
				
				rdbtnNewRadioButton_4 = new JRadioButton("Tournament selection");
				selectorRadioButtons.add(rdbtnNewRadioButton_4);
				panel.add(rdbtnNewRadioButton_4, "cell 0 3 2 1");

				lblTournamentGroupSize = new JLabel("Tournament group size:");
				panel.add(lblTournamentGroupSize, "cell 0 4");

				spinner_8 = new JSpinner();
				panel.add(spinner_8, "cell 1 4,growx");
				
				ActionListener al = new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent e) {
						if(e.getSource() == rdbtnNewRadioButton_4){
							spinner_8.setEnabled(true);
						}else{
							spinner_8.setEnabled(false);
						}
					}
				};
				
				rdbtnNewRadioButton_4.addActionListener(al);
				rdbtnSelectUsingGaussian.addActionListener(al);
				rdbtnSelectUsingExponential.addActionListener(al);
			}
		}
		{
			JPanel panel = new JPanel();
			tabbedPane.addTab("Crosser", null, panel, null);
			panel.setLayout(new MigLayout("", "[][]", "[][][][]"));
			{
				JLabel lblCrossoverProbability = new JLabel("Crossover probability (%)");
				panel.add(lblCrossoverProbability, "cell 0 0");
			}
			{
				spinner_6 = new JSpinner();
				panel.add(spinner_6, "cell 1 0,growx");
			}
			{
				chckbxRandomizeNumberOf = new JCheckBox("Randomize number of cross points");
				panel.add(chckbxRandomizeNumberOf, "cell 0 1 2 1");
				JLabel lblNumberOfCross = new JLabel("Number of cross points:");
				panel.add(lblNumberOfCross, "cell 0 2");
				spinner = new JSpinner();
				panel.add(spinner, "cell 1 2,growx");
				
				chckbxRandomizeNumberOf.addChangeListener(new ChangeListener() {
					@Override
					public void stateChanged(ChangeEvent e) {
						spinner.setEnabled(!((JCheckBox)e.getSource()).isSelected());
					}
				});
			}
			{
				chckbxEnableEntityNormalization = new JCheckBox("Enable entity normalization");
				panel.add(chckbxEnableEntityNormalization, "cell 0 3 2 1");
			}
		}
		{
			JPanel panel = new JPanel();
			tabbedPane.addTab("Mutator", null, panel, null);
			panel.setLayout(new MigLayout("", "[][50px:n:50px]", "[]"));
			{
				JLabel lblMutationProbability = new JLabel("Mutation probability (%)");
				panel.add(lblMutationProbability, "cell 0 0");
			}
			{
				spinner_7 = new JSpinner();
				panel.add(spinner_7, "cell 1 0,growx");
			}
		}
		JPanel buttonPane = new JPanel();
		buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
		getContentPane().add(buttonPane, BorderLayout.SOUTH);
		{
			JButton okButton = new JButton("OK");
			okButton.addActionListener(new ActionListener() {
				@Override
				public void actionPerformed(ActionEvent arg0) {
					setOKEvent();
				}
			});
			okButton.setActionCommand("OK");
			buttonPane.add(okButton);
			getRootPane().setDefaultButton(okButton);
		}
	}

	public JSpinner getPopulationSizeSpinner() {
		return spinner_1;
	}
	public JRadioButton getEvaluationWithRepairRadioButton() {
		return rdbtnNewRadioButton;
	}
	public JRadioButton getEvaluationWithPunishmentRadioButton() {
		return rdbtnNewRadioButton_1;
	}
	public JSpinner getEvaluatorPunishmentSpinner() {
		return spinner_2;
	}
	public JRadioButton getGenerationLimitRadioButton() {
		return rdbtnNewRadioButton_2;
	}
	public JRadioButton getGenerationsWithoutImprovementRadioButton() {
		return rdbtnNewRadioButton_3;
	}
	public JSpinner getGenerationsLimitSpinner() {
		return spinner_3;
	}
	public JSpinner getGenerationsWithoutImprovementLimitSpinner() {
		return spinner_4;
	}
	public JRadioButton getSelectUsingGaussianRadioButton() {
		return rdbtnSelectUsingGaussian;
	}
	public JRadioButton getSelectUsingExponentialRadioButton() {
		return rdbtnSelectUsingExponential;
	}
	public JSpinner getSelectionFactorSpinner() {
		return spinner_5;
	}
	public JSpinner getCrossoverProbabilitySpinner() {
		return spinner_6;
	}
	public JCheckBox getRandomizeNumberOfCrossPointsCheckBox() {
		return chckbxRandomizeNumberOf;
	}
	public JSpinner getNumberOfCrossPointsSpinner() {
		return spinner;
	}
	public JCheckBox getEnableEntityNormalizationCheckBox() {
		return chckbxEnableEntityNormalization;
	}
	public JSpinner getMutationProbabilitySpinner() {
		return spinner_7;
	}
	public JRadioButton getTournamentSelectionRadioButton() {
		return rdbtnNewRadioButton_4;
	}
	public JSpinner getTournamentGroupSizeSpinner() {
		return spinner_8;
	}
}
